﻿//
// Creator: Jickie阿文
//

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;

namespace JBT.Library.Utilities
{

    public enum MSIME:uint
    {
        China = 0,
        Taiwan = 1,
        Japan = 2,
        Korea= 3
    }
    public static class Extensions
    {
        public static string GetName(this MSIME value)
        {
            return string.Format("{0}.{1}", typeof(MSIME).Name, Enum.GetName(typeof(MSIME), value));
        }
    }

    //**************************************************************************************
    // IFELanguage Interface
    //**************************************************************************************
    [ComImport]
    [Guid("019F7152-E6DB-11D0-83C3-00C04FDDB82E")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface IFELanguage
    {
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        int Open();
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        int Close();
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        int GetJMorphResult(uint dwRequest, uint dwCMode, int cwchInput,
            [MarshalAs(UnmanagedType.LPWStr)] string pwchInput, IntPtr pfCInfo, out IntPtr ppResult);
    } // end of IFELanguage Interface

    /// <summary>
    /// MSIMEProvider
    /// </summary>
    public class MSIMEProvider:IDisposable
    {
        private bool FInitialized = false;

        private const int S_OK = 0;
        private const int CLSCTX_LOCAL_SERVER = 4;
        private const int CLSCTX_INPROC_SERVER = 1;
        private const int CLSCTX_INPROC_HANDLER = 2;
        private const int CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER;
        private const int FELANG_REQ_REV = 0x00030000;
        private const int FELANG_CMODE_PINYIN = 0x00000100;
        private const int FELANG_CMODE_NOINVISIBLECHAR = 0x40000000;

        [DllImport("ole32.dll")]
        private static extern int CLSIDFromString([MarshalAs(UnmanagedType.LPWStr)] string lpsz, out Guid pclsid);

        [DllImport("ole32.dll")]
        private static extern int CoCreateInstance([MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
            IntPtr pUnkOuter, uint dwClsContext, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IntPtr rpv);

        [DllImport("ole32.dll")]
        private static extern int CoInitialize(IntPtr pvReserved);

        [DllImport("ole32.dll")]
        private static extern int CoUninitialize();




        //-------------------------------------------------------------------------------------
        // Constructor
        public MSIMEProvider()
        {
            int res = CoInitialize(IntPtr.Zero);

            if (res == S_OK)
                FInitialized = true;
        }

        public void Dispose()
        {
            if (FInitialized)
            {
                CoUninitialize();
                FInitialized = false;
            }
        }

        // Destructor
        ~MSIMEProvider()
        {
            if (FInitialized)
                CoUninitialize();
        }

        public string GetReadString(string value, MSIME imetype = MSIME.China)
        {
            if (string.IsNullOrEmpty(value))
            {
                return value;
            }
            string readString = String.Empty;
            Guid pclsid;
            int res;

            //  Get CLSID's pointer from text's CLSID
            res = CLSIDFromString(imetype.GetName(), out pclsid);

            if (res != S_OK)
            {
                this.Dispose();
                return readString;
            }

            Guid riid = new Guid("019F7152-E6DB-11D0-83C3-00C04FDDB82E ");
            IntPtr ppv;
            res = CoCreateInstance(pclsid, IntPtr.Zero, CLSCTX_SERVER, riid, out ppv);

            if (res != S_OK)
            {
                this.Dispose();
                return readString;
            }

            IFELanguage language = Marshal.GetTypedObjectForIUnknown(ppv, typeof(IFELanguage)) as IFELanguage;
            res = language.Open();

            if (res != S_OK)
            {
                this.Dispose();
                return readString;
            }

            IntPtr result;

            res = language.GetJMorphResult(FELANG_REQ_REV, FELANG_CMODE_PINYIN | FELANG_CMODE_NOINVISIBLECHAR,
                    value.Length, value, IntPtr.Zero, out result);

            if (res != S_OK)
            {
                this.Dispose();
                return readString;
            }

            readString = Marshal.PtrToStringUni(Marshal.ReadIntPtr(result, 4), Marshal.ReadInt16(result, 8));

            language.Close();

            return readString;
        }

    } // end of ImeLanguage class

}